package com.guli.mall.pms.service.impl;
/*
 * @Author 罗
 * @date 2020/10/17 - 9:59 上午
 */

import com.guli.common.constant.ProductAttrTypeEnum;
import com.guli.common.constant.ProductEnum;
import com.guli.common.pojo.SeckillSkuRelationEntity;
import com.guli.common.to.SecKillSessionAndRelation;
import com.guli.mall.pms.entity.*;
import com.guli.mall.pms.entity.vo.AttrGroupAndAttrVo;
import com.guli.mall.pms.entity.vo.ItemDetailVo;
import com.guli.mall.pms.entity.vo.SaleAttrAndSkuMapVo;
import com.guli.mall.pms.entity.vo.SkuInfoWithSaleEntitiesVo;
import com.guli.mall.pms.feign.SecKillFeignClient;
import com.guli.mall.pms.service.*;
import com.guli.mall.serviceBase.globalException.MallException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SkuInfoServiceForFrontPageImpl implements SkuInfoServiceForFrontPage {


    @Resource
    SkuInfoService skuInfoService;

    @Resource
    SkuImagesService skuImagesService;

    @Resource
    SkuSaleAttrValueService skuSaleAttrValueService;

    @Resource
    AttrGroupService attrGroupService;

    @Resource
    SpuInfoService spuInfoService;

    @Resource
    SpuImagesService spuImagesService;

    @Resource
    SpuInfoDescService spuInfoDescService;

    @Resource
    ExecutorService executorService;


    @Resource
    SecKillFeignClient secKillFeignClient;


    @Override
    public ItemDetailVo getAllSkuDetailBySkuId(Long skuId) throws Throwable {

        CompletableFuture<List<SkuImagesEntity>> skuImagesFuture = CompletableFuture.supplyAsync(() -> {
            List<SkuImagesEntity> skuImagesEntities = skuImagesService.getImagesBySkuId(skuId);
            log.info("skuId = {}，的图片列表查询完成", skuId);
            return skuImagesEntities;
        }, executorService);

        CompletableFuture<List<SkuSaleAttrValueEntity>> saleAttrFuture = CompletableFuture.supplyAsync(() -> {

            List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = skuSaleAttrValueService.getSaleAttrsBySkuId(skuId);
            log.info("skuId = {}，的销售属性查询完成", skuId);
            return skuSaleAttrValueEntities;
        }, executorService);

        CompletableFuture<SkuInfoEntity> querySkuInfoTask = CompletableFuture.supplyAsync(() -> {
            SkuInfoEntity skuInfo = skuInfoService.getByIdAndAddImgPredix(skuId);
            log.info("skuId = {}，的商品查询完成", skuId);
            if (ObjectUtils.isEmpty(skuInfo)) {
                throw new MallException("未查询到skuId = " + skuId + "，的商品");
            }
            return skuInfo;

        }, executorService);

        // 查询该商品是否参与秒杀（并返回秒杀的场次信息）
        CompletableFuture<List<SecKillSessionAndRelation>> queryIsSecKillTask = querySkuInfoTask.thenApplyAsync(skuInfo -> {

            return secKillFeignClient.checkWhetherTheProductParticipatesInTheSpike(skuInfo.getSpuId().toString());

        }, executorService);


        CompletableFuture<List<SkuInfoEntity>> otherSkuInfoFuture = querySkuInfoTask.thenApplyAsync((skuInfo) -> {

            List<SkuInfoEntity> skuInfoEntities = skuInfoService.getSkuListBySpuIdAndAddImgPredix(skuInfo.getSpuId());

            log.info("与spuId = {}相同的sku查询完成", skuInfo.getSpuId());

            return skuInfoEntities;

        }, executorService);


        CompletableFuture<List<SkuInfoWithSaleEntitiesVo>> queryOtherSkuInfoAndSaleAttrFuture = otherSkuInfoFuture.thenApply(skuInfoEntities -> {

            List<SkuInfoWithSaleEntitiesVo> otherSkuInfoAndItsSaleAttr = skuSaleAttrValueService.appendSkuSaleAttrsToEachSkuInfo(skuInfoEntities);

            log.info("其他sku和其对应的saleAttr已经查询完毕");

            return otherSkuInfoAndItsSaleAttr;
        });

        CompletableFuture<HashMap<String, SaleAttrAndSkuMapVo>> saleAttrAndSkuMapFuture = queryOtherSkuInfoAndSaleAttrFuture.thenApply(SkuInfoWithSaleEntitiesVoList -> {

            HashMap<String, SaleAttrAndSkuMapVo> saleAttrAndSkuMap = parseSaleAttr(SkuInfoWithSaleEntitiesVoList);

            return saleAttrAndSkuMap;
        });


        CompletableFuture<List<AttrGroupAndAttrVo>> attrGroupAndAttrValueIndexFuture = querySkuInfoTask.thenApplyAsync(skuInfo -> {

            AttrEntity attrEntity = new AttrEntity();

            attrEntity.setAttrType(ProductAttrTypeEnum.BASIC_ATTRIBUTE.getValue());

            List<AttrGroupAndAttrVo> attrGroupAndItsAttrList = attrGroupService.querySpuInfoAttrValueAndFillIntoAttrGroup(skuInfo.getSpuId());

            log.info("查询到该skuId = {}对应 spuId = {}下的属性分组以及属性还有属性值", skuId, skuInfo.getSpuId());

            return attrGroupAndItsAttrList;
        }, executorService);

        // 查询 spu
        CompletableFuture<SpuInfoEntity> spuInfoEntityCompletableFuture = querySkuInfoTask.thenApplyAsync(skuInfo -> {

            SpuInfoEntity spuInfo = spuInfoService.getById(skuInfo.getSpuId());

            return spuInfo;
        }, executorService);

        // 查询 spu 下的 sku 的图片
        CompletableFuture<List<SpuImagesEntity>> spuImagesFuture = spuInfoEntityCompletableFuture.thenApplyAsync(spuInfo -> {
            return spuImagesService.getBySpuIdAndAddImagePrefix(spuInfo.getId());
        }, executorService);

        // 查询 spuInfoDesc 下的 spu 封面图片，并封装成 spuImages
        CompletableFuture<List<SpuImagesEntity>> combineDescAndImagesFuture = spuInfoEntityCompletableFuture.thenApply(spuInfo -> {
            List<SpuImagesEntity> list = spuInfoDescService.getBySpuIdAndAddImgPrefixAndEncapsulateToSpuImagesEntityList(spuInfo.getId());
            return list;

        }).thenCombine(spuImagesFuture, (spuDescImgList, spuImages) -> {
            //封装 spuInfoDesc中的图片和 spuImages中的图片，
            if (CollectionUtils.isEmpty(spuDescImgList)) {
                return spuDescImgList;
            }
            spuDescImgList.addAll(spuImages);
            return spuDescImgList;
        });

        CompletableFuture<Void> allFuture = CompletableFuture.allOf(
                skuImagesFuture,
                saleAttrFuture,
                otherSkuInfoFuture,
                attrGroupAndAttrValueIndexFuture,
                queryOtherSkuInfoAndSaleAttrFuture,
                spuInfoEntityCompletableFuture,
                combineDescAndImagesFuture,
                saleAttrAndSkuMapFuture,
                queryIsSecKillTask);

        try {
            Void unused = allFuture.get();
        } catch (Exception e) {
            throw e.getCause() instanceof MallException ? (MallException) e.getCause() : e.getCause();
        }


        ItemDetailVo itemDetailVo = new ItemDetailVo();

        itemDetailVo.setCurrentSkuImages(skuImagesFuture.get());

        itemDetailVo.setSaleAttrs(saleAttrFuture.get());

        itemDetailVo.setSkuInfo(querySkuInfoTask.get());

        //itemDetailVo.setSameLevelSkuInfoList(otherSkuInfoFuture.get());
        itemDetailVo.setSameLevelSkuInfoList(queryOtherSkuInfoAndSaleAttrFuture.get());

        itemDetailVo.setAttrs(attrGroupAndAttrValueIndexFuture.get());

        itemDetailVo.setSpuInfo(spuInfoEntityCompletableFuture.get());

        itemDetailVo.setSpuImages(combineDescAndImagesFuture.get());

        itemDetailVo.setSaleAttrAndSkuMap(saleAttrAndSkuMapFuture.get());

        // 使用 sentinel 对 feign 熔断之后，就不用捕获异常了
        itemDetailVo.setSecKillSessionAndRelations(queryIsSecKillTask.get());

        /*
        没有添加 feign熔断机制的时候需要这样捕获异常
        try {
            itemDetailVo.setSecKillSessionAndRelations(queryIsSecKillTask.get());
        } catch (Exception e) {
            log.warn("查询 skuId = {}的秒杀信息失败，不影响商品查询服务的执行",skuId);
        }*/


        return itemDetailVo;
    }

    /**
     * 解析Sku 所拥有的 销售属性(saleAttr)，
     *
     * @param skuInfoWithSaleEntitiesVoList
     * @return key：销售属性的value（attrValue），value：拥有该销售属性的 sku的id
     */
    private HashMap<String, SaleAttrAndSkuMapVo> parseSaleAttr(List<SkuInfoWithSaleEntitiesVo> skuInfoWithSaleEntitiesVoList) {


        HashMap<String, SaleAttrAndSkuMapVo> saleAttrAndSkuMap = new HashMap<>();

        skuInfoWithSaleEntitiesVoList.forEach(skuInfo -> {

            if (!CollectionUtils.isEmpty(skuInfo.getSaleAttrList())) {

                skuInfo.getSaleAttrList().forEach(saleAttr -> {

                    // 判断map中有没有 key = attrValue 的对象
                    SaleAttrAndSkuMapVo saleAttrAndSkuMapVo = saleAttrAndSkuMap.get(saleAttr.getAttrValue());

                    if (ObjectUtils.isEmpty(saleAttrAndSkuMapVo)) {

                        SaleAttrAndSkuMapVo saleAttrAndSkuMapVoNew = new SaleAttrAndSkuMapVo();

                        saleAttrAndSkuMapVoNew.setSaleAttrId(saleAttr.getAttrId());

                        saleAttrAndSkuMapVoNew.setSkuIdListContainingSaleAttrValue(new ArrayList<>());

                        // 因为新增时，SaleAttrAndSkuMapVo 中不可能存在重复的 skuId，所以直接添加
                        saleAttrAndSkuMapVoNew.getSkuIdListContainingSaleAttrValue().add(skuInfo.getSkuId());

                        saleAttrAndSkuMap.put(saleAttr.getAttrValue(), saleAttrAndSkuMapVoNew);
                    } else {

                        // map 中已经存在 该 SaleAttrAndSkuMapVo ，因为 skuId不可能被添加两次，所以可以直接添加
                        saleAttrAndSkuMapVo.getSkuIdListContainingSaleAttrValue().add(skuInfo.getSkuId());

                    }

                });
            }

        });

        return saleAttrAndSkuMap;
    }
}
